/**
 * Copyright (C) 2009 Matteo Merli <mm@merlimat.org>
 * 
 * $Id: PxlFloat.java 24 2009-01-19 19:49:05Z matteo.merli $
 * $URL: http://pxl-lang.googlecode.com/svn/trunk/src/main/java/pxl/types/PxlFloat.java $
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package pxl.types;

import java.util.Collection;
import java.util.Map;

import pxl.errors.InvalidComparison;
import pxl.errors.UnsupportedOperand;
import pxl.types.annotations.Exported;

/**
 * @author Matteo Merli
 */
public final class PxlFloat extends PxlObject
{

    private double value;

    public PxlFloat( double value )
    {
        this.value = value;
    }

    @Override
    public String getType()
    {
        return "float";
    }

    @Override
    public String toString()
    {
        return Double.toString( value );
    }

    public static PxlFloat fromString( String repr )
    {
        double value = Double.parseDouble( repr );
        return new PxlFloat( value );
    }

    public double getValue()
    {
        return value;
    }

    // // Operators

    @Override
    @Exported
    public PxlString __repr__()
    {
        return new PxlString( toString() );
    }

    @Override
    @Exported
    public PxlString __str__()
    {
        return __repr__();
    }

    @Override
    @Exported
    public PxlObject __add__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
            return new PxlFloat( value + ((PxlFloat) other).value );
        else if ( other instanceof PxlInteger )
            return new PxlFloat( value + ((PxlInteger) other).getValue() );
        else
            throw new UnsupportedOperand( "+", this, other );
    }

    @Override
    @Exported
    public PxlObject __mul__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
            return new PxlFloat( value * ((PxlFloat) other).value );
        else if ( other instanceof PxlInteger )
            return new PxlFloat( value * ((PxlInteger) other).getValue() );
        else
            throw new UnsupportedOperand( "*", this, other );
    }

    @Override
    @Exported
    public PxlObject __truediv__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
            return new PxlFloat( value / ((PxlFloat) other).value );
        else if ( other instanceof PxlInteger )
            return new PxlFloat( value / ((PxlInteger) other).getValue() );
        else
            throw new UnsupportedOperand( "/", this, other );
    }

    @Override
    @Exported
    public PxlObject __floordiv__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
            return new PxlFloat( Math.floor( value / ((PxlFloat) other).value ) );
        else if ( other instanceof PxlInteger )
            return new PxlFloat( Math.floor( value
                    / ((PxlInteger) other).getValue() ) );
        else
            throw new UnsupportedOperand( "/", this, other );
    }

    @Exported
    @Override
    public PxlTuple __divmod__( PxlObject other )
    {
        if ( other instanceof PxlInteger )
        {
            long o = ((PxlInteger) other).getValue();
            return new PxlTuple( new PxlFloat( (long) (value / o) ),
                    new PxlFloat( value % o ) );
        }
        else if ( other instanceof PxlFloat )
        {
            double o = ((PxlFloat) other).getValue();
            return new PxlTuple( new PxlFloat( (long) (value / o) ),
                    new PxlFloat( value % o ) );
        }
        else
            throw new UnsupportedOperand( "divmod", this, other );
    }

    @Override
    @Exported
    public PxlObject __sub__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
            return new PxlFloat( value - ((PxlFloat) other).value );
        else if ( other instanceof PxlInteger )
            return new PxlFloat( value - ((PxlInteger) other).getValue() );
        else
            throw new UnsupportedOperand( "-", this, other );
    }

    @Override
    @Exported
    public PxlObject __mod__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
            return new PxlFloat( value % ((PxlFloat) other).value );
        else if ( other instanceof PxlInteger )
            return new PxlFloat( value % ((PxlInteger) other).getValue() );
        else
            throw new UnsupportedOperand( "%", this, other );
    }

    @Override
    @Exported
    public PxlBoolean __bool__()
    {
        return value == 0.0 ? PxlBoolean.False : PxlBoolean.True;
    }

    @Exported
    @Override
    public PxlObject __not__()
    {
        return PxlBoolean.not( __bool__() );
    }

    @Exported
    @Override
    public PxlObject __pos__()
    {
        return this;
    }

    @Exported
    @Override
    public PxlObject __neg__()
    {
        return new PxlFloat( -value );
    }

    @Exported
    @Override
    public PxlObject __abs__()
    {
        return new PxlFloat( Math.abs( value ) );
    }

    @Exported
    @Override
    public PxlObject __int__()
    {
        return new PxlInteger( (long) value );
    }

    @Exported
    @Override
    public PxlObject __float__()
    {
        return new PxlFloat( value );
    }

    // Comparison

    @Exported
    @Override
    public PxlBoolean __eq__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
        {
            return PxlBoolean.valueOf( value == ((PxlFloat) other).getValue() );
        }
        else if ( !(other instanceof PxlInteger) )
            return PxlBoolean.False;
        long otherValue = ((PxlInteger) other).getValue();
        return PxlBoolean.valueOf( value == otherValue );
    }

    @Exported
    @Override
    public PxlBoolean __neq__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
        {
            return PxlBoolean.valueOf( value != ((PxlFloat) other).getValue() );
        }
        else if ( !(other instanceof PxlInteger) )
            return PxlBoolean.True;
        long otherValue = ((PxlInteger) other).getValue();
        return PxlBoolean.valueOf( value != otherValue );
    }

    @Exported
    @Override
    public PxlBoolean __lt__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
        {
            return PxlBoolean.valueOf( value < ((PxlFloat) other).getValue() );
        }
        else if ( !(other instanceof PxlInteger) )
            throw new InvalidComparison( this, other );
        long otherValue = ((PxlInteger) other).getValue();
        return PxlBoolean.valueOf( value < otherValue );
    }

    @Exported
    @Override
    public PxlBoolean __lte__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
        {
            return PxlBoolean.valueOf( value <= ((PxlFloat) other).getValue() );
        }
        else if ( !(other instanceof PxlInteger) )
            throw new InvalidComparison( this, other );
        long otherValue = ((PxlInteger) other).getValue();
        return PxlBoolean.valueOf( value <= otherValue );
    }

    @Exported
    @Override
    public PxlBoolean __gt__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
        {
            return PxlBoolean.valueOf( value > ((PxlFloat) other).getValue() );
        }
        else if ( !(other instanceof PxlInteger) )
            throw new InvalidComparison( this, other );
        long otherValue = ((PxlInteger) other).getValue();
        return PxlBoolean.valueOf( value > otherValue );
    }

    @Exported
    @Override
    public PxlBoolean __gte__( PxlObject other )
    {
        if ( other instanceof PxlFloat )
        {
            return PxlBoolean.valueOf( value >= ((PxlFloat) other).getValue() );
        }
        else if ( !(other instanceof PxlInteger) )
            throw new InvalidComparison( this, other );
        long otherValue = ((PxlInteger) other).getValue();

        return PxlBoolean.valueOf( value >= otherValue );
    }

    // Attributes

    private static final Map<String, PxlObject> attrs = PxlObject
            .getExportedMethods( PxlFloat.class );

    @Override
    protected PxlObject getAttribute( String name )
    {
        return attrs.get( name );
    }

    @Override
    protected Collection<String> getAttributeNames()
    {
        return attrs.keySet();
    }

}
